/*
  S.M.A.C.K - An operating system kernel
  Copyright (C) 2010,2011 Mattias Holm and Kristian Rietveld
  For licensing and a full list of authors of the kernel, see the files
  COPYING and AUTHORS.
*/

#include <stdio.h>
#include <process.h>
#include <interrupt.h>
#include <timer.h>
#include <console.h>
#include <device.h>
#include <bootparam.h>
#include <idle.h>
#include <panic.h>


static void
start_init(void)
{
  proc_t *p;
  uint32_t flags;

  /* Interrupts must be disabled between proc_load() and proc_schedule(),
   * otherwise context can be switched to the new process in between
   * and proc_schedule() will return NULL.
   */
  flags = save_flags();
  disable_interrupts();

  p = proc_create(NULL);
  if (proc_load(p, "/init") < 0)
    {
      puts("Could not launch init.\n");
      panic();
    }

  proc_t *next_proc = proc_schedule();
  /* Some schedulers could choose to still run idle first ... */
  if (proc_current() != next_proc)
    proc_switch(next_proc);

  restore_flags(flags);
}


void __attribute__((noreturn))
boot(void)
{
  /* Boot parameters are initialized before the MMU, because it might
   * need to communicate with the boot loader somehow in the future.
   */
  bootparam_init();

  vm_init();
  /* No serial I/O can happen (puts, etc.) from here until serial_init()
   * is called below.
   */
  interrupt_init();
  console_init();

  // Serial driver should now be initialised
  puts("Booting system");
  puts("MMU enabled; console alive");

  timer_init();
  puts("Timer enabled");

  enable_interrupts();
  puts("IRQ enabled");

  // Initialise Virtual File System
  vfs_init();
  puts("VFS initialised");

  // Init device driver layer
  dev_init();
  puts("Device driver system initialised");

  puts("Starting VFS");

  vfs_mount_root();
  puts("Root file system mounted");

  /* Launch init */
  start_init();

  /* Start kernel idle task */
  idle();
}
